﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data;

/**
 * @file DecisionData.cs Содержит реализацию вспомогательного класса. 
 *                      Для осуществления подписки к БД через Service Broker (SqlDependency)
 * @author Максим Терентьев
 */

namespace AccidentCards
{
    /** @class DecisionData
     * @anchor DecisionData
     * @brief Класс реализует немедленное получение данных с сервера БД, 
     * в случае добавления, изменения, удаления таковых
     * @details Получение данных происходит через механизм подписки к серверу баз данных
     * по средствам Service Broker (SqlDependency)
     */
    public class AccidentData
    {
        private SqlConnection m_sqlConn = null;

        /** @fn void NewMessage()
         * @anchor NewMessage
         * @brief Делегат пользовательского события @ref OnNewMessage
         * @details Делегирует вызоа пользовательской @b void функции
         */
        public delegate void NewMessage();
        /** @var event NewMessage OnNewMessage
         * @anchor OnNewMessage
         * @brief Пользовательское событие вызываемое при добавлении, 
         * изменении либо удалении объекта подписки
         */
        public event NewMessage OnNewMessage;

        /** @fn DecisionData()
        * @brief Конструктор класса 
        * @details Создает подписку
        */
        public AccidentData()
        {
            // Stop an existing services on this connection string just be sure
            //SqlDependency.Stop(dbServices.globalConnectionString);
            
            // Start the dependency
            // User must have SUBSCRIBE QUERY NOTIFICATIONS permission
            //SqlDependency.Start(dbServices.globalConnectionString);

            // Create the connection
            m_sqlConn = new SqlConnection(dbServices.globalConnectionString);
        }

        /** @fn ~DecisionData()
        * @brief Деструктор класса 
        * @details Закрывает подключение
        */
        ~AccidentData()
        {
            // Stop the dependency before exiting
            //SqlDependency.Stop(dbServices.globalConnectionString);
        }

        /** @fn DataTable GetMessages(DateTime? p_datettime)
         * @brief Получает все сообщения по подписке, начиная с определенного момента
         * @details Получает все сообщения, начиная с момента startDate, на основе логики, реализованной в БД.
         * @param[in] p_datettime - временная точка начала, либо @b null если необходимо показать все
         * @return Возвращает таблицу данных, соответствующую критериям подписки
         */
        public DataTable GetMessages(DateTime? p_datettime)
        {
            DataTable dt = new DataTable();

            try
            {
                // Create command
                SqlCommand cmd = new SqlCommand("GetAccidentData", m_sqlConn);
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(new SqlParameter("@start_date", SqlDbType.DateTime2));
                cmd.Parameters["@start_date"].Value = p_datettime ?? new DateTime(DateTime.MinValue.Ticks);

                /*
// Clear any existing notifications
                cmd.Notification = null;

                // Create the dependency for this command
                SqlDependency dependency = new SqlDependency(cmd);

                // Add the event handler
                dependency.OnChange += new OnChangeEventHandler(OnChange);
*/

                // Open the connection if necessary
                if(m_sqlConn.State == ConnectionState.Closed)
                    m_sqlConn.Open();

                // Get the messages
                dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));

                // Set Primary key
                dt.PrimaryKey = new DataColumn[] { dt.Columns[0] };
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return dt;
        }

        /** void OnChange(object sender, SqlNotificationEventArgs e)
        * @brief Обработчик для события SqlDependency OnChange
        * @details Вызывает пользовательское событие @ref OnNewMessage
        * @see OnNewMessage
        */
        void OnChange(object sender, SqlNotificationEventArgs e)
        {
            SqlDependency dependency = sender as SqlDependency;
            
            // Notices are only a one shot deal
            // so remove the existing one so a new 
            // one can be added
            dependency.OnChange -= OnChange;

            // Fire the event
            if (OnNewMessage != null)
            {
                OnNewMessage();
            }
        }

    }
}
